<?php


namespace EchoPHP\Rabbitmq;


use EchoPHP\Foundation\Application;
use EchoPHP\Support\Arr;

class RabbitMqManager {

    /**
     * 应用容器实例
     * @var Application
     */
    protected $app;

    /**
     * 已连接实例合集
     * @var RabbitMqConnection[]
     */
    protected $connections = [];

    public function __construct($app) {
        $this->app = $app;
    }

    /**
     * 析构函数，释放连接
     */
    public function __destruct() {
        foreach ($this->connections as $connection) {
            $connection->disconnect();
        }
        $this->connections = [];
    }

    /**
     * 连接rabbitmq
     * @param null $name
     * @return RabbitMqConnection
     * @throws \Exception
     */
    public function connect($name) {
        $name = $this->getConnectionName($name);
        if (!isset($this->connections[$name])) {
            $this->connections[$name] = $this->makeConnection($name);
        }
        return $this->connections[$name];
    }

    /**
     * 释放连接
     * @param null $name
     */
    public function disconnect($name) {
        $name = $this->getConnectionName($name);
        if (isset($this->connections[$name])) {
            $this->connections[$name]->disconnect();
        }
    }

    /**
     * 重新连接
     * @param null $name
     * @return mixed
     * @throws \Exception
     */
    public function reconnect($name) {
        $name = $this->getConnectionName($name);

        $this->disconnect($name);
        if (!isset($this->connections[$name])) {
            return $this->connect($name);
        }
        $this->connections[$name] = $this->makeConnection($name);
    }

    /**
     * 获取连接名称
     * @param null $name
     * @return string
     */
    protected function getConnectionName($name = null) {
        return $name;
    }

    /**
     * 新建连接
     * @param $name
     * @return RabbitMqConnection
     * @throws \Exception
     */
    protected function makeConnection($name) {
        $config = $this->getConfiguration($name);
        $connector = $this->createConnector($name, $config['credential']);
        return $this->createConnection($connector, $config);
    }

    /**
     * 获取连接配置
     * @param $name
     * @return array
     * @throws \Exception
     */
    protected function getConfiguration($name) {
        $config = config('rabbitmq');
        if (!isset($config['businesses'][$name]) || !is_array($config['businesses'][$name])) {
            throw new \Exception('队列业务逻辑未声明;业务名:[' . $name . ']');
        }
        $businessConfig = $config['businesses'][$name];
        $credentialConfig = Arr::get($config, 'credentials.' . $businessConfig['credential']);
        if (empty($credentialConfig)) {
            throw new \Exception('连接认证未定义;业务名:[' . $name . ']');
        }
        //交换机不是必须定义的，可以使用匿名交换机
        if (!isset($businessConfig['exchange']) || empty($businessConfig['exchange'])) {
            $businessConfig['exchange'] = null;
            $exchangeConfig = [];
        } else {
            $exchangeConfig = Arr::get($config, 'exchanges.' . $businessConfig['exchange']);
            if (empty($exchangeConfig)) {
                throw new \Exception('exchange未定义;业务名:[' . $name . ']');
            }
        }

        $queueConfig = $businessConfig['queues'] ?? null;
        unset($businessConfig['queues']);
        if (empty($queueConfig)) {
            throw new \Exception('queues未定义;业务名:[' . $name . ']');
        }

        return $config = [
            'business' => $businessConfig,
            'credential' => $credentialConfig,
            'exchange' => $exchangeConfig,
            'queues' => $queueConfig,
        ];
    }

    /**
     * 创建连接器
     * @param $name
     * @param $config
     * @return \AMQPConnection
     */
    protected function createConnector($name, $config) {
        $connector = new QueueConnector();
        return $connector->connect($name, $config);
    }

    /**
     * 创建连接实例
     * @param $connector
     * @param array $config
     * @return RabbitMqConnection
     */
    protected function createConnection($connector, array $config) {
        return new RabbitMqConnection($connector, $config);
    }


}